﻿using MetaProperties.Core;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MetaProperties.Framework;
using System.Collections.Generic;

namespace MetaProperties.Core.Tests
{
    using System.Linq;

    /// <summary>
    ///This is a test class for MetaPropertyHostTest and is intended
    ///to contain all MetaPropertyHostTest Unit Tests
    ///</summary>
    [TestClass()]
    public class MetaPropertyHostTest
    {


        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        // 
        //You can use the following additional attributes as you write your tests:
        //
        //Use ClassInitialize to run code before running the first test in the class
        //[ClassInitialize()]
        //public static void MyClassInitialize(TestContext testContext)
        //{
        //}
        //
        //Use ClassCleanup to run code after all tests in a class have run
        //[ClassCleanup()]
        //public static void MyClassCleanup()
        //{
        //}
        //
        //Use TestInitialize to run code before running each test
        //[TestInitialize()]
        //public void MyTestInitialize()
        //{
        //}
        //
        //Use TestCleanup to run code after each test has run
        //[TestCleanup()]
        //public void MyTestCleanup()
        //{
        //}
        //
        #endregion


        /// <summary>
        ///A test for MetaProperties
        ///</summary>
        [TestMethod()]
        public void MetaPropertiesTest()
        {
            IMetaPropertyHost target = new TestMetaPropertyHost();
            IEnumerable<IMetaProperty> actual;
            actual = target.MetaProperties;

            Assert.AreEqual(2, actual.Count());
        }

        /// <summary>
        ///A test for OnPropertyChanged
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void OnPropertyChangedTest()
        {
            TestMetaPropertyHost host = new TestMetaPropertyHost();
            PrivateObject param0 = new PrivateObject(host, new PrivateType(typeof(MetaPropertyHost)));
            MetaPropertyHost_Accessor target = new MetaPropertyHost_Accessor(param0);

            string propertyName = "TestPropertyName";

            bool eventCalled = false;
            host.PropertyChanged += (s, e) =>
            {
                eventCalled = true;
                Assert.AreEqual(propertyName, e.PropertyName);
            };

            target.OnPropertyChanged(propertyName);

            Assert.IsTrue(eventCalled);
        }

        /// <summary>
        ///A test for GetMetaProperty
        ///</summary>
        [TestMethod()]
        public void GetMetaPropertyTest()
        {
            TestMetaPropertyHost target = new TestMetaPropertyHost();
            string propertyName = "Test2";

            IMetaProperty actual = target.GetMetaProperty(propertyName);

            Assert.IsNotNull(actual);
            Assert.AreEqual(propertyName, actual.PropertyName);
            Assert.AreEqual(target, actual.Host);

            Assert.AreEqual(0, actual.UntypedValue);

            target.Test2 = 6;

            Assert.AreEqual(6, actual.UntypedValue);
        }

        /// <summary>
        ///A test for CreateDependency
        ///</summary>
        [TestMethod()]
        [DeploymentItem("MetaProperties.Core.dll")]
        public void CreateDependencyTest()
        {
            TestMetaPropertyHost host = new TestMetaPropertyHost();
            PrivateObject param0 = new PrivateObject(host);
            MetaPropertyHost_Accessor target = new MetaPropertyHost_Accessor(param0);
            
            target.CreateDependency("Dependency", host.TestProperty, host.Test2Property);

            List<string> changedProperties = new List<string>();

            host.PropertyChanged += (s, e) => changedProperties.Add(e.PropertyName);

            host.Test = 100;

            Assert.IsTrue(changedProperties.Contains("Test"));
            Assert.IsTrue(changedProperties.Contains("Dependency"));
            Assert.IsFalse(changedProperties.Contains("Test2"));

            changedProperties.Clear();

            host.Test2 = 300;

            Assert.IsFalse(changedProperties.Contains("Test"));
            Assert.IsTrue(changedProperties.Contains("Dependency"));
            Assert.IsTrue(changedProperties.Contains("Test2"));
        }

        private class TestMetaPropertyHost : MetaPropertyHost
        {
            Observable<int> notifyingTest = new Observable<int>();

            Observable<int> notifyingTest2 = new Observable<int>();

            Observable<int> notifyingTest3 = new Observable<int>();

            public TestMetaPropertyHost()
            {
                this.Initialize(notifyingTest3.MetaProperty);
            }

            public int Test
            {
                get { return this.notifyingTest.Value; }
                set { this.notifyingTest.Value = value; }
            }

            public IMetaProperty<int> TestProperty
            {
                get { return this.notifyingTest.MetaProperty; }
            }

            //[MetaPropertyFilter(typeof(DispatchingEventFilter))]
            //[SetSynchronizationContextContainer(null)]
            public int Test2
            {
                get { return this.notifyingTest2.Value; }
                set { this.notifyingTest2.Value = value; }
            }

            public IMetaProperty<int> Test2Property
            {
                get { return this.notifyingTest2.MetaProperty; }
            }
        }
    }
}
